#include "list.h"

#include <stdbool.h>
#include <stdlib.h>

typedef struct Node_t Node_t;

struct Node_t
{
    Node_t*         priv;
    Node_t*         next;
    ListElementType data;
};

struct List_t
{
    int     size;
    Node_t* head;
    Node_t* back;
};

// 内部函数

Node_t* node_create(ListElementType value);
void    node_distory(Node_t* node);

inline static Node_t* node_create(ListElementType value) {
    Node_t* node = malloc(sizeof(Node_t));
    if (node == NULL)
        return NULL;

    node->priv = NULL;
    node->next = NULL;
    node->data = value;
    return node;
}
inline static void node_distory(Node_t* node) {
    if (node) {
        free(node);
    }
}
//

List_t* list_create(void) {
    List_t* list = malloc(sizeof(List_t));
    if (list == NULL) {
        return NULL;
    }

    list->head = list->back = NULL;
    list->size = 0;
    return list;
}

void list_distory(List_t* list) {
    if (list == NULL)
        return;
    list_clear(list);
    free(list);
}

bool list_empty(List_t* list) {
    if (list == NULL)
        return true;
    return list->size == 0;
}

void list_clear(List_t* list) {
    if (list == NULL)
        return;

    while (list->head) {
        Node_t* p = list->head;
        list->head = list->head->next;
        free(p);
        --list->size;
        
    }
}

bool list_push(List_t* list, ListElementType element) {
    if (list == NULL) {
        return false;
    }
    Node_t* new_node = node_create(element);
    if (new_node == NULL) {
        return false;
    }

    if (list->size == 0) {
        list->head = list->back = new_node;
    }
    else {
        list->back->next = new_node;
        new_node->priv = list->back;
        list->back = new_node;
    }

    ++list->size;

    return true;
}

bool list_pop(List_t* list, ListElementType* element) {
    if (list == NULL) {
        return false;
    }
    if (list->back) {
        Node_t* p = list->back;

        list->back = list->back->priv;
        if (list->back)
            list->back->next = NULL;
        
        --list->size;

        if (list->size == 0)
            list->head = list->back = 0;

        ListElementType data = p->data;
        node_distory(p);

        if (element) {
            *element = data;
        }
        return true;
    }
    return false;
}

bool list_push_front(List_t* list, ListElementType element) {
    if (list == NULL) {
        return false;
    }
    Node_t* new_node = node_create(element);

    if (list->size == 0) {
        list->head = list->back = new_node;
    }
    else {
        list->head->priv = new_node;
        new_node->next = list->head;
        list->head = new_node;
    }
    ++list->size;

    return true;
}

bool list_pop_front(List_t* list, ListElementType* element) {
    if (list == NULL) {
        return false;
    }
    if (list->head) {
        Node_t* p = list->head;

        list->head = list->head->next;
        if (list->head)
            list->head->priv = NULL;
        --list->size;
        if (list->size == 0)
            list->head = list->back = 0;

        ListElementType data = p->data;
        node_distory(p);

        if (element) {
            *element = data;
        }
        return true;
    }
    return false;
}